package cheme.ProcessModel.Interpreter;

import java.util.Iterator;

import cheme.ProcessModel.IModelElement;
import cheme.ProcessModel.ModelEnv;
import cheme.ProcessModel.ProcessModelConstants;
import cheme.ProcessModel.Annotations.Annotation;
import cheme.ProcessModel.Equations.Equation;
import cheme.ProcessModel.Interpreter.IRule.RuleResult;
import cheme.ProcessModel.ProcessUnits.Streams.Tags.ITagComponent;
import cheme.ProcessModel.Table.Field;

public abstract class EquationIteratingRule implements IRule
{
	protected Interpreter interpreter = null;
	private Equation equation = null;

	protected abstract RuleResult tokenCheck(Field equationToken);
	//protected abstract String getCommonUnit();
		
	public RuleResult applyTo(IModelElement object)
	{
		RuleResult result = null;
		RuleResult Oldresult = null;
		
		if(object instanceof Equation)
		{
			setEquation((Equation)object);
			interpreter = ModelEnv.getInstanceFor(getEquation()).getInterpreter();
			
			Iterator<Field> iterator =  getEquation().iterator();//.getChildren().iterator();
			Iterator<Field> typeCheckiterator =  getEquation().iterator();
			Field field = null;			
			boolean bTest = false;
						
			while(iterator.hasNext()&& ((null == result) ||  (result instanceof IRule.Success)) ) //((null == result) ||
			{
				bTest = false;
				// if the type of element is not field then return
				// this was dded to avoid the crash due to moving of equation 
				if ( typeCheckiterator.hasNext() && !(typeCheckiterator.next() instanceof Field))
				{
					return result;
				}
				field = iterator.next();
				while(field.getText().isEmpty()&& iterator.hasNext()){
					// if field is empty then put old result in result
					result = Oldresult;
					//continue;
					field = iterator.next();
				}
				if(!(field.getText().isEmpty()))
				{
					result = tokenCheck(field);
					// update Old result with the latest result
					Oldresult = result;
				}
				else
				{
					result = Oldresult;
					continue;
				}
				
				// PA Change
				// Reset the failure result it unit is of % type and there are still some elements in the equation
				if(result instanceof IRule.Failure && iterator.hasNext() && !(bTest))
				{
					// get current unit
					ModelElementData modelData = interpreter.getModelData(field.getText());
					if(null != modelData){
						ITagComponent referencedTagComponent = (ITagComponent)modelData.getModel();
						String currentUnit = referencedTagComponent.getUnits();
						String material = referencedTagComponent.getMaterial();;
						if (currentUnit.trim().equals("%") || material.equals("Overall"))
						{
							bTest = true;
							result = null;						
						}
					}
				}
				// PA change Ends
			}
		}
		//String commonUnit = getCommonUnit();
		/*if(null != commonUnit)
		{
			if( !(commonUnit.isEmpty()) && commonUnit.equals("%"))
			{
				result = new IRule.Failure(getEquation(), "You can not have equations like % = % + % or % = % * %.\n Please correct your equation by making changes like % * OverAlll.");
			}
		}*/
		
		setAnnotation(result);
		return result;
	}

	/**
	 * @param equation the equation to set
	 */
	public void setEquation(Equation equation)
	{
		this.equation = equation;
	}

	/**
	 * @return the equation
	 */
	public Equation getEquation()
	{
		return equation;
	}
	
	public void setAnnotation(RuleResult result)
	{
		//interpreter = ModelEnv.getInstanceFor(getEquation()).getInterpreter();
		ModelElementData modelData = interpreter.getModelData(getEquation());
		
		if ( null != modelData)
		{
			if(result instanceof IRule.Success)
			{
				
				interpreter.removeEntry(result.getSource());	
				modelData.setErrorAnnotation(null);
			}
			else
			{
				if (null != result){
				String strmsg = interpreter.updateConsoleMap(result);
				modelData.setErrorAnnotation(new Annotation(getEquation(), ProcessModelConstants.DESC_WARNING, result.getMessage(),strmsg));
				}
			}
		}
	}
}